package cn.kennylee.codehub.mybatis.codegenerator;

import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.SystemUtil;
import cn.kennylee.codehub.mybatis.das.eo.BaseEo;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.builder.Controller;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.builder.Entity;
import com.baomidou.mybatisplus.generator.config.builder.Service;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;

import java.io.File;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 代码生成器
 * <p>Created on 2025/3/14.</p>
 *
 * @author kennylee
 * @since 0.0.1
 */
public class MybatisPlusGenerator {

    private static final String MYSQL_URL = "jdbc:mysql://127.0.0.1:3306";
    // 数据库scheme
    private static final String MYSQL_SCHEMA = "shop";
    private static final String MYSQL_USERNAME = "root";
    private static final String MYSQL_PASSWORD = "abc12345";

    private static final String EO_AUTHOR = "代码生成器";
    private static final String TABLE_PREFIX = "t_";

    private static final String ENTITY_SUFFIX = "Eo";

    // 是否构建到dist目录
    private static final boolean isBuildToDist = true;

    /**
     * 执行代码生成器
     */
    public static void main(String[] args) {

        // 需要生成的表列表
        List<String> tables = List.of(
            //"t_member", "t_shop"
        );

        // 包名
        String parentPackage = MybatisPlusGenerator.class.getPackage().getName();
        // 模块名
        String modulePackageName = "shop";

        // java输出目录
        Path javaOutputDir = isBuildToDist ? getProjectRootDir().resolve("dist").resolve("generator") :
            getJavaRootDir();
        // 资源文件输出目录
        Path resourceOutputDir = isBuildToDist ? javaOutputDir :
            getJavaResourcesDir();

        Path mapperPath = resourceOutputDir.resolve("mapper");

        // 模块全包名
        String fullModulePackageName = parentPackage + StrPool.DOT + modulePackageName;

        Path packageAbsolutPath = getPackageAbsolutPath(javaOutputDir, fullModulePackageName);
        System.out.println(packageAbsolutPath.toAbsolutePath());

        // 自定义模板生成文件的路径
        Map<OutputFile, String> pathInfoConfig = new HashMap<>() {
            {
                put(OutputFile.xml, mapperPath.toAbsolutePath().toString());
            }
        };

        FastAutoGenerator.create(
                // 数据源配置
                MYSQL_URL + "/" + MYSQL_SCHEMA,
                MYSQL_USERNAME,
                MYSQL_PASSWORD
            )
            // 全局配置
            .globalConfig(builder -> {
                builder.author(EO_AUTHOR)
                    //.enableSpringdoc()
                    // 输出目录
                    .outputDir(javaOutputDir.toAbsolutePath().toString());
            })
            // 包配置
            .packageConfig(builder -> {
                builder.parent(fullModulePackageName)
                    .pathInfo(
                        pathInfoConfig
                    );
            })
            // 数据库类型转换配置
            .dataSourceConfig(builder -> {
                builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
                    // 如果是tinyint类型，转换为INTEGER
                    if (metaInfo.getJdbcType().name().toLowerCase().contains("tinyint")) {
                        return DbColumnType.INTEGER;
                    }
                    // 其他类型使用MySQL的默认转换
                    return new MySqlTypeConvert().processTypeConvert(globalConfig, metaInfo.getJdbcType().name());
                });
            })
            // 策略配置
            .strategyConfig(builder -> {
                Entity.Builder entityBuilder = builder
                    // 指定表名生成，空列表或注释就是全部
                    .addInclude(tables)
                    // 增加过滤表前缀
                    .addTablePrefix(TABLE_PREFIX)
                    .entityBuilder()
                    .addIgnoreColumns(List.of("id"))
                    .enableLombok()
                    .enableColumnConstant()
                    .formatFileName("%s" + ENTITY_SUFFIX)
                    .javaTemplate("mytemplates/entity.java")
                    .superClass(BaseEo.class);

                // 配置service类
                Service.Builder serviceBuilder = entityBuilder.serviceBuilder()
                    // 去掉Service接口的I前缀
                    .formatServiceFileName("%sService")
                    .serviceTemplate("mytemplates/service.java")
                    .serviceImplTemplate("mytemplates/serviceImpl.java");

                Controller.Builder controllerBuilder = serviceBuilder.controllerBuilder()
                    .formatFileName("%sController")  // 确保Controller不包含Eo后缀
                    .enableRestStyle()  // 启用REST风格
                    .template("mytemplates/controller.java");
            })
            // 注入配置（自定义）
            .injectionConfig(builder -> {
                // 配置das
                CustomFile dasTemplateFile = new CustomFile.Builder()
                    .fileName("Das.java")
                    .formatNameFunction((tableInfo) -> escapeEntitySuffix(tableInfo.getEntityName()))
                    .packageName("das")
                    .templatePath("mytemplates/das.java.vm")
                    .build();

                // 配置dsl
                CustomFile dslTemplateFile = new CustomFile.Builder()
                    .fileName("Dsl.java")
                    .formatNameFunction((tableInfo) -> escapeEntitySuffix(tableInfo.getEntityName()))
                    .packageName("dsl")
                    .templatePath("mytemplates/dsl.java.vm")
                    .build();

                // 配置dto
                CustomFile dtoTemplateFile = new CustomFile.Builder()
                    .fileName("Dto.java")
                    .formatNameFunction((tableInfo) -> escapeEntitySuffix(tableInfo.getEntityName()))
                    .packageName("dto")
                    .templatePath("mytemplates/dto.java.vm")
                    .build();

                // 添加自定义的文件
                List<CustomFile> customFiles = List.of(
                    dasTemplateFile, dslTemplateFile, dtoTemplateFile
                );
                builder.customFile(customFiles);

                // 增加自定义模板常量
                Map<String, Object> customMap = new HashMap<>();
                customMap.put("StrUtil", StrUtil.class);
                customMap.put("entitySuffix", ENTITY_SUFFIX);

                builder.customMap(customMap);
            })
            .execute();
    }

    public static String escapeEntitySuffix(String entityName) {
        // 删掉最后的Entity后缀
        return StrUtil.removeSuffix(entityName, ENTITY_SUFFIX);
    }

    /**
     * 获取包绝对路径
     *
     * @param outputDir     输出目录
     * @param parentPackage 父包名
     * @return 包绝对路径
     */
    private static Path getPackageAbsolutPath(Path outputDir, String parentPackage) {
        String fileSeparator = SystemUtil.getOsInfo().getFileSeparator();
        return Path.of(outputDir.toAbsolutePath() + fileSeparator + parentPackage.replace(StrPool.DOT, fileSeparator));
    }

    /**
     * 获取java根目录
     *
     * @return java根目录
     */
    private static Path getJavaRootDir() {
        return getProjectRootDir().resolve("src").resolve("main").resolve("java");
    }

    /**
     * 获取resource目录
     *
     * @return resources根目录
     */
    private static Path getJavaResourcesDir() {
        return getProjectRootDir().resolve("src").resolve("main").resolve("resources");
    }

    /**
     * 获取test根目录
     *
     * @return java根目录
     */
    private static Path getTestRootDir() {
        return getProjectRootDir().resolve("test").resolve("main").resolve("java");
    }

    /**
     * 获取resource目录
     *
     * @return resources根目录
     */
    private static Path getTestResourcesDir() {
        return getProjectRootDir().resolve("test").resolve("main").resolve("resources");
    }

    /**
     * 获取项目根路径
     *
     * @return 项目根路径
     */
    private static Path getProjectRootDir() {
        return new File(MybatisPlusGenerator.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getParentFile().getParentFile().toPath();
    }
}
